package com.company.test29;

import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by v on 16-11-28.
 */
public class Test2910 {
    private static Buffer buffer=new Buffer();

    public static void main(String[] args) {
        ExecutorService executor= Executors.newFixedThreadPool(2);
        executor.execute(new ProducerTask());
        executor.execute(new ConsumerTask());
        executor.shutdown();
    }

    private static class ProducerTask implements Runnable{
        @Override
        public void run() {
            try {
                int i=1;
                while (true){
                    System.out.println("Produce writes "+i);
                    buffer.write(i++);

                    Thread.sleep((int)(1000*Math.random()));
                }
            }catch (InterruptedException ex){
                ex.printStackTrace();
            }
        }
    }

    private static class ConsumerTask implements Runnable{
        @Override
        public void run() {
            try {
                while (true){
                    System.out.println("\t\t\t\tConsumer reads "+buffer.read());

                    Thread.sleep(1000);
                }
            }catch (InterruptedException ex){
                ex.printStackTrace();
            }
        }
    }

    private static class Buffer{
        private static final int CAPACITY=1;//buffer size
        public LinkedList<Integer> queue=new LinkedList<>();

        public static Lock lock=new ReentrantLock();

        private static Condition notEmpty=lock.newCondition();
        private static Condition notFull=lock.newCondition();

        public void write(int value){
            lock.lock();
            try{
                while (queue.size()==CAPACITY){
                    System.out.println("Wait for notFull condition");
                    notFull.await();
                }

                queue.offer(value);
                notEmpty.signalAll();
            }catch (InterruptedException ex){
                ex.printStackTrace();
            }finally {
                lock.unlock();
            }
        }

        public int read(){
            int value=0;
            lock.lock();
            try {
                while (queue.size()==0){
                    System.out.println("Wait for notEmpty condition");
                    notEmpty.await();
                }

                value=queue.pop();
                notFull.signalAll();
            }catch (InterruptedException ex){
                ex.printStackTrace();
            }finally {
                lock.unlock();
                return value;
            }
        }
    }
}
